import yfinance as yf¶

import pandas as pd

data = yf.download('RELIANCE.NS', start='2023-01-01', end='2024-01-01')

print(data)

In [3]:
data.describe()
Out[3]:
Price Close High Low Open Volume SMA50 SMA200 Signal
Ticker RELIANCE.NS RELIANCE.NS RELIANCE.NS RELIANCE.NS RELIANCE.NS
count 245.000000 245.000000 245.000000 245.000000 2.450000e+02 196.000000 46.000000 245.000000
mean 1158.515832 1167.544031 1150.101075 1159.618830 1.342906e+07 1155.458936 1154.968559 0.187755
std 68.996361 69.028158 68.241882 67.986717 6.566007e+06 58.423981 6.880815 0.391316
min 1008.876465 1017.469976 999.137156 1015.178381 3.854810e+06 1067.407145 1148.026281 0.000000
25% 1113.739990 1121.027318 1105.627760 1115.504712 9.209636e+06 1093.980308 1148.742854 0.000000
50% 1155.154419 1163.078321 1151.940330 1157.188818 1.203256e+07 1168.875358 1152.738733 0.000000
75% 1209.391479 1217.368326 1203.415681 1211.886930 1.578266e+07 1203.694152 1159.946151 0.000000
max 1302.476196 1308.961472 1289.050059 1301.133996 5.708188e+07 1243.968442 1170.063072 1.000000
In [5]:
import yfinance as yf
import matplotlib.pyplot as plt

# Download historical data for Reliance Industries Limited
ticker = "RELIANCE.NS"
data = yf.download(ticker, start="2023-01-01", end="2024-01-01")

# Plot closing prices
plt.figure(figsize=(12, 6))
plt.plot(data.index, data['Close'], label='Close Price', color='blue',marker='o')
plt.title(f'{ticker} Trade Chart (2024)')
plt.xlabel('Date')
plt.ylabel('Price (INR)')
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()
[*********************100%***********************]  1 of 1 completed
No description has been provided for this image
In [7]:
data.info()
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 245 entries, 2023-01-02 to 2023-12-29
Data columns (total 5 columns):
 #   Column                 Non-Null Count  Dtype  
---  ------                 --------------  -----  
 0   (Close, RELIANCE.NS)   245 non-null    float64
 1   (High, RELIANCE.NS)    245 non-null    float64
 2   (Low, RELIANCE.NS)     245 non-null    float64
 3   (Open, RELIANCE.NS)    245 non-null    float64
 4   (Volume, RELIANCE.NS)  245 non-null    int64  
dtypes: float64(4), int64(1)
memory usage: 11.5 KB
In [19]:
import yfinance as yf
import pandas as pd


data = yf.download('RELIANCE.NS', start='2023-01-01', end='2024-01-01')


# Preview the data
print(data)
[*********************100%***********************]  1 of 1 completed
Price             Close         High          Low         Open      Volume
Ticker      RELIANCE.NS  RELIANCE.NS  RELIANCE.NS  RELIANCE.NS RELIANCE.NS
Date                                                                      
2023-01-02  1180.586060  1182.006865  1167.890577  1168.715541     5316175
2023-01-03  1171.946655  1179.256896  1167.707271  1175.613232     7658932
2023-01-04  1154.301392  1173.780010  1152.216007  1171.923749     9264891
2023-01-05  1152.239014  1162.482516  1147.632911  1156.570169    13637099
2023-01-06  1162.711548  1167.776018  1154.186834  1158.013796     6349597
...                 ...          ...          ...          ...         ...
2023-12-22  1278.186890  1286.085010  1269.516244  1275.471131    16541784
2023-12-26  1284.664917  1291.591360  1277.015829  1279.656890     7465664
2023-12-27  1289.050049  1295.552881  1282.198303  1286.633203     9204156
2023-12-28  1298.368408  1301.582475  1289.050059  1290.520045    12302636
2023-12-29  1288.103149  1302.579043  1285.287754  1301.133996    10864584

[245 rows x 5 columns]

In [1]:
import yfinance as yf
import plotly.graph_objects as go

def plot_candlestick_range(ticker, start_date, end_date):
    
    try:
        data = yf.download(ticker, start=start_date, end=end_date)

        fig = go.Figure(data=[go.Candlestick(x=data.index,
                                             open=data['Open'],
                                             high=data['High'],
                                             low=data['Low'],
                                             close=data['Close'])])

        fig.update_layout(
            title=f'{ticker} Candlestick Chart ({start_date} to {end_date})',
            xaxis_title='Date',
            yaxis_title='Price (INR)',
            xaxis_rangeslider_visible=False
        )
        fig.show()

    except Exception as e:
        print(f"An error occurred: {e}")
        print(f"Could not retrieve data for {ticker} between {start_date} and {end_date}. Please check the ticker symbol or date range.")

if __name__ == "__main__":
    stock_ticker = "RELIANCE.NS"
    start_date = "2023-01-01"
    end_date = "2024-01-01"
    plot_candlestick_range(stock_ticker, start_date, end_date)
YF.download() has changed argument auto_adjust default to True
[*********************100%***********************]  1 of 1 completed

1 Failed download:
['RELIANCE.NS']: YFRateLimitError('Too Many Requests. Rate limited. Try after a while.')
In [17]:
import yfinance as yf
import pandas as pd

# Download historical data
data = yf.download('INFOSYS.NS', start='2023-01-01', end='2024-01-01')

# Calculate moving averages
data['SMA50'] = data['Close'].rolling(window=50).mean()
data['SMA200'] = data['Close'].rolling(window=200).mean()

# Generate trading signals
data['Signal'] = 0  
data.loc[data['SMA50'] > data['SMA200'], 'Signal'] = 1  
data.loc[data['SMA50'] < data['SMA200'], 'Signal'] = -1  

print(data[['Close', 'SMA50', 'SMA200', 'Signal']].tail(10))
[*********************100%***********************]  1 of 1 completed
Price             Close        SMA50       SMA200 Signal
Ticker      RELIANCE.NS                                 
Date                                                    
2023-12-15  1243.579346  1173.710940  1161.310849      1
2023-12-18  1256.236328  1175.772444  1162.140546      1
2023-12-19  1274.723633  1178.204189  1163.088803      1
2023-12-20  1259.300903  1180.288613  1163.922823      1
2023-12-21  1276.941162  1182.922676  1164.881366      1
2023-12-22  1278.186890  1185.480496  1165.949947      1
2023-12-26  1284.664917  1187.802615  1167.001992      1
2023-12-27  1289.050049  1190.169084  1168.116869      1
2023-12-28  1298.368408  1192.722917  1169.142331      1
2023-12-29  1288.103149  1195.123767  1170.063072      1

In [23]:
import yfinance as yf
import pandas as pd
import numpy as np
#ZSCORE

def calculate_z_score(series, window):
    rolling_mean = series.rolling(window=window).mean()
    rolling_std = series.rolling(window=window).std()
    return (series - rolling_mean) / rolling_std

def pairs_trading_strategy(ticker1, ticker2, lookback_window, entry_threshold, exit_threshold):

    data = yf.download([f"{ticker1}.NS", f"{ticker2}.NS"], period="1y")['Close']
    data = data.dropna()

    
    spread = data[f"{ticker1}.NS"] - data[f"{ticker2}.NS"]

    
    z_score = calculate_z_score(spread, window=lookback_window)

    
    signals = pd.DataFrame(index=z_score.index)
    signals['position'] = 0

    signals.loc[z_score < -entry_threshold, 'position'] = 1
    signals.loc[z_score > entry_threshold, 'position'] = -1 
    signals.loc[(signals['position'].shift(1) == 1) & (z_score > -exit_threshold), 'position'] = 0
    signals.loc[(signals['position'].shift(1) == -1) & (z_score < exit_threshold), 'position'] = 0

    
    return signals, z_score


ticker1 = "RELIANCE"
ticker2 = "TCS"
lookback = 20
entry = 2
exit = 0

signals, z_scores = pairs_trading_strategy(ticker1, ticker2, lookback, entry, exit)
print(signals)
print(z_scores)
[*********************100%***********************]  2 of 2 completed
            position
Date                
2024-04-25         0
2024-04-26         0
2024-04-29         0
2024-04-30         0
2024-05-02         0
...              ...
2025-04-21         0
2025-04-22         0
2025-04-23         0
2025-04-24         0
2025-04-25         0

[248 rows x 1 columns]
Date
2024-04-25         NaN
2024-04-26         NaN
2024-04-29         NaN
2024-04-30         NaN
2024-05-02         NaN
                ...   
2025-04-21    1.192566
2025-04-22    1.098692
2025-04-23    0.413799
2025-04-24    0.442566
2025-04-25    0.036431
Length: 248, dtype: float64

In [25]:
def bollinger_bands_strategy(ticker, period=20, std_dev=2, lookback="30d"):
    
    df = yf.download(f"{ticker}.NS", period=lookback)
    if df.empty:
        print(f"Could not retrieve data for {ticker} for the period: {lookback}.")
        return pd.DataFrame()

    
    close_prices = df['Close'].dropna()
    

    print("\nShape of 'close_prices' (pandas Series):", close_prices.shape)
    print("First few rows of 'close_prices':\n", close_prices.head())

    
    indicator = ta.volatility.BollingerBands(close=close_prices, window=period, window_dev=std_dev)
    bb_mid = indicator.bollinger_mavg()
    bb_upper = indicator.bollinger_hband()
    bb_lower = indicator.bollinger_lband()

    results_df = pd.DataFrame({'Close': close_prices, 'bb_mid': bb_mid, 'bb_upper': bb_upper, 'bb_lower': bb_lower})

    import yfinance as yf
import pandas as pd
import ta
import numpy as np

def bollinger_bands_strategy(ticker, period=20, std_dev=2, lookback="30d"):
    
    df = yf.download(f"{ticker}.NS", period=lookback)
    if df.empty:
        print(f"Could not retrieve data for {ticker} for the period: {lookback}.")
        return pd.DataFrame()

    
    close_prices = df['Close'].dropna()

    print("\nShape of 'close_prices' (pandas Series):", close_prices.shape)
    print("First few rows of 'close_prices':\n", close_prices.head())


    indicator = ta.volatility.BollingerBands(close=close_prices, window=period, window_dev=std_dev)
    bb_mid = indicator.bollinger_mavg()
    bb_upper = indicator.bollinger_hband()
    bb_lower = indicator.bollinger_lband()

    
    results_df = pd.DataFrame({'Close': close_prices, 'bb_mid': bb_mid, 'bb_upper': bb_upper, 'bb_lower': bb_lower})
    results_df['squeeze_on'] = (results_df['bb_upper'] - results_df['bb_lower']) <= (results_df['bb_mid'].rolling(period).std() * 2)
    results_df['squeeze_breakout_long'] = (results_df['Close'] > results_df['bb_upper']) & (results_df['squeeze_on'].shift(1) == True)
    results_df['squeeze_breakout_short'] = (results_df['Close'] < results_df['bb_lower']) & (results_df['squeeze_on'].shift(1) == True)

    return results_df[['Close', 'bb_lower', 'bb_mid', 'bb_upper', 'squeeze_on', 'squeeze_breakout_long', 'squeeze_breakout_short']]

if __name__ == "__main__":
    ticker = "RELIANCE"
    results_df = bollinger_bands_strategy(ticker, lookback="30d")
    if not results_df.empty:
        print("\nShape of results_df in main:", results_df.shape)
        print("First few rows of results_df in main:\n", results_df.head())
        print("\nLast few rows of results_df in main:\n", results_df.tail())
    else:
        print("Could not generate Bollinger Bands.")

    # Simulate new data arrival
    today = pd.Timestamp('today').strftime('%Y-%m-%d')
    yesterday = (pd.Timestamp('today') - pd.Timedelta(days=1)).strftime('%Y-%m-%d')
    new_data_df = yf.download(f"{ticker}.NS", start=yesterday, end=today)['Close'].dropna()

    if not new_data_df.empty:
        last_price = new_data_df.iloc[-1]
        new_row = pd.Series({'Close': last_price})
        if not results_df.empty:
            results_df = pd.concat([results_df, new_row.to_frame().T], ignore_index=False)
            # Recalculate indicators
            indicator = ta.volatility.BollingerBands(close=results_df['Close'], window=20, window_dev=2)
            results_df['bb_mid'] = indicator.bollinger_mavg()
            results_df['bb_upper'] = indicator.bollinger_hband()
            results_df['bb_lower'] = indicator.bollinger_lband()
            results_df['squeeze_on'] = (results_df['bb_upper'] - results_df['bb_lower']) <= (results_df['bb_mid'].rolling(20).std() * 2)
            results_df['squeeze_breakout_long'] = (results_df['Close'] > results_df['bb_upper']) & (results_df['squeeze_on'].shift(1) == True)
            results_df['squeeze_breakout_short'] = (results_df['Close'] < results_df['bb_lower']) & (results_df['squeeze_on'].shift(1) == True)

            print("\nShape of updated results_df:", results_df.shape)
            print("\nLast few rows of updated results_df:\n", results_df.tail())
        else:
            print("\nInitial DataFrame was empty, cannot append new data.")
    else:
        print("\nCould not fetch new daily data for simulation.")
[*********************100%***********************]  1 of 1 completed
Shape of 'close_prices' (pandas Series): (30, 1)
First few rows of 'close_prices':
 Ticker      RELIANCE.NS
Date                   
2025-03-10  1238.400024
2025-03-11  1247.300049
2025-03-12  1257.050049
2025-03-13  1247.900024
2025-03-17  1238.849976
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[25], line 57
     55 if __name__ == "__main__":
     56     ticker = "RELIANCE"
---> 57     results_df = bollinger_bands_strategy(ticker, lookback="30d")
     58     if not results_df.empty:
     59         print("\nShape of results_df in main:", results_df.shape)

Cell In[25], line 43, in bollinger_bands_strategy(ticker, period, std_dev, lookback)
     39 print("First few rows of 'close_prices':\n", close_prices.head())
     42 indicator = ta.volatility.BollingerBands(close=close_prices, window=period, window_dev=std_dev)
---> 43 bb_mid = indicator.bollinger_mavg()
     44 bb_upper = indicator.bollinger_hband()
     45 bb_lower = indicator.bollinger_lband()

File ~\anaconda3\Lib\site-packages\ta\volatility.py:108, in BollingerBands.bollinger_mavg(self)
    102 """Bollinger Channel Middle Band
    103 
    104 Returns:
    105     pandas.Series: New feature generated.
    106 """
    107 mavg = self._check_fillna(self._mavg, value=-1)
--> 108 return pd.Series(mavg, name="mavg")

File ~\anaconda3\Lib\site-packages\pandas\core\series.py:584, in Series.__init__(self, data, index, dtype, name, copy, fastpath)
    582         data = data.copy()
    583 else:
--> 584     data = sanitize_array(data, index, dtype, copy)
    586     manager = _get_option("mode.data_manager", silent=True)
    587     if manager == "block":

File ~\anaconda3\Lib\site-packages\pandas\core\construction.py:633, in sanitize_array(data, index, dtype, copy, allow_2d)
    631     else:
    632         data = np.array(data, copy=copy)
--> 633     return sanitize_array(
    634         data,
    635         index=index,
    636         dtype=dtype,
    637         copy=False,
    638         allow_2d=allow_2d,
    639     )
    641 else:
    642     _sanitize_non_ordered(data)

File ~\anaconda3\Lib\site-packages\pandas\core\construction.py:659, in sanitize_array(data, index, dtype, copy, allow_2d)
    656             subarr = cast(np.ndarray, subarr)
    657             subarr = maybe_infer_to_datetimelike(subarr)
--> 659 subarr = _sanitize_ndim(subarr, data, dtype, index, allow_2d=allow_2d)
    661 if isinstance(subarr, np.ndarray):
    662     # at this point we should have dtype be None or subarr.dtype == dtype
    663     dtype = cast(np.dtype, dtype)

File ~\anaconda3\Lib\site-packages\pandas\core\construction.py:718, in _sanitize_ndim(result, data, dtype, index, allow_2d)
    716     if allow_2d:
    717         return result
--> 718     raise ValueError(
    719         f"Data must be 1-dimensional, got ndarray of shape {data.shape} instead"
    720     )
    721 if is_object_dtype(dtype) and isinstance(dtype, ExtensionDtype):
    722     # i.e. NumpyEADtype("O")
    724     result = com.asarray_tuplesafe(data, dtype=np.dtype("object"))

ValueError: Data must be 1-dimensional, got ndarray of shape (30, 1) instead
In [33]:
import yfinance as yf
import pandas as pd
import ta

def calculate_rsi(ticker, period=14, lookback="100d"):
    
    df = yf.download(ticker, period=lookback)
    if df.empty:
        print(f"Could not retrieve data for {ticker}.")
        return None

    
    close_prices = df['Close'].squeeze().dropna()

    rsi_indicator = ta.momentum.RSIIndicator(close=close_prices, window=period)
    rsi = rsi_indicator.rsi()

    rsi_df = pd.DataFrame({'Close': close_prices, 'RSI': rsi})

    return rsi_df

if __name__ == "__main__":
    stock_ticker = "RELIANCE.NS"  
    rsi_period = 14
    historical_lookback = "365d"  

    rsi_data = calculate_rsi(stock_ticker, period=rsi_period, lookback=historical_lookback)

    if rsi_data is not None:
        print(f"RSI for {stock_ticker} (Period: {rsi_period}, Lookback: {historical_lookback}):")
        print(rsi_data.tail(20))  
    else:
        print("RSI calculation failed.")

close_prices = df['Close'].squeeze().dropna()
[*********************100%***********************]  1 of 1 completed
RSI for RELIANCE.NS (Period: 14, Lookback: 365d):
                  Close        RSI
Date                              
2025-03-25  1285.449951  61.661602
2025-03-26  1273.050049  57.554981
2025-03-27  1278.199951  58.782744
2025-03-28  1275.099976  57.700779
2025-04-01  1252.599976  50.443446
2025-04-02  1251.150024  50.006949
2025-04-03  1248.699951  49.231717
2025-04-04  1204.699951  37.875811
2025-04-07  1165.699951  31.041225
2025-04-08  1182.199951  36.280004
2025-04-09  1185.349976  37.259945
2025-04-11  1218.949951  46.679461
2025-04-15  1240.099976  51.604866
2025-04-16  1239.300049  51.411433
2025-04-17  1274.500000  58.740390
2025-04-21  1295.500000  62.385612
2025-04-22  1291.199951  61.193431
2025-04-23  1300.000000  62.761782
2025-04-24  1301.599976  63.054141
2025-04-25  1300.400024  62.656829

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[33], line 35
     32     else:
     33         print("RSI calculation failed.")
---> 35 close_prices = df['Close'].squeeze().dropna()

NameError: name 'df' is not defined
In [35]:
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt


data = yf.download('RELIANCE.NS', start='2023-01-01', end='2024-01-01')


def calculate_rsi(data, window=14):
    delta = data['Close'].diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
    rs = gain / loss
    rsi = 100 - (100 / (1 + rs))
    return rsi

data['RSI'] = calculate_rsi(data)

# Plot RSI
plt.figure(figsize=(12, 6))
plt.plot(data['RSI'], label='RSI', color='blue')
plt.axhline(70, color='red', linestyle='--', label='Overbought Threshold')
plt.axhline(30, color='green', linestyle='--', label='Oversold Threshold')
plt.title('RSI of Reliance Stock (RELIANCE.NS)')
plt.xlabel('Date')
plt.ylabel('RSI')
plt.legend()
plt.grid()
plt.show()
[*********************100%***********************]  1 of 1 completed
No description has been provided for this image
In [37]:
import numpy as np
import pandas as pd
import yfinance as yf
import ta  

def calculate_returns(df, risk_free_rate=0.06):
    """Calculates  Annualized and Cumulative returns for a given DataFrame with 'Close' prices.

    Args:
        df (pd.DataFrame): DataFrame containing 'Close' prices.
        risk_free_rate (float): Annual risk-free rate (default: 0.06).

    Returns:
        pd.Series: A Series containing the calculated returns.
    """
    returns = df['Close'].pct_change().dropna()
    n = len(returns)
    trading_days = 252  # Approximate number of trading days in a year

    # Cumulative Return
    cumulative_return = (1 + returns).prod() - 1

    # Annualized Return
    annualized_return = ((1 + cumulative_return) ** (trading_days / n)) - 1

    return pd.Series({
        'Cumulative Return': cumulative_return,
        'Annualized Return': annualized_return,

    })


def get_stock_returns(ticker, risk_free_rate=0.06, period="1y"):
    """Fetches stock data and calculates returns.

    Args:
        ticker (str): Stock ticker symbol.
        risk_free_rate (float): Annual risk-free rate (default: 0.06).
        period (str): The time period for which to retrieve stock data.
                        Valid values are yfinance period strings (e.g., "1y", "5y", "max").
    Returns:
        pd.DataFrame:  containing the returns, or None if data retrieval fails.
    """
    try:
        df = yf.download(ticker, period=period)
        if df.empty:
            print(f"No data found for ticker: {ticker}")
            return None
        returns_series = calculate_returns(df, risk_free_rate)
        print(returns_series) 

        # Create a DataFrame for the returns with date
        returns_df = pd.DataFrame(returns_series).transpose()
        returns_df.index = [ticker]  
        return returns_df

    except Exception as e:
        print(f"Error fetching data or calculating returns for {ticker}: {e}")
        return None



if __name__ == '__main__':
    # Example usage
    stock_ticker = 'RELIANCE.NS'  
    risk_free_rate = 0.06
    returns_df = get_stock_returns(stock_ticker, risk_free_rate)

    if returns_df is not None:
        print(f"Returns for {stock_ticker}:")
        print(returns_df)  
    else:
        print(f"Could not retrieve returns for {stock_ticker}")
[*********************100%***********************]  1 of 1 completed
Cumulative Return    Ticker
RELIANCE.NS   -0.106277
dtype: float64
Annualized Return    Ticker
RELIANCE.NS   -0.108307
dtype: float64
dtype: object
Returns for RELIANCE.NS:
                                         Cumulative Return  \
RELIANCE.NS  Ticker
RELIANCE.NS   -0.106277
dtype: float64   

                                         Annualized Return  
RELIANCE.NS  Ticker
RELIANCE.NS   -0.108307
dtype: float64  

In [39]:
import yfinance as yf
import numpy as np
import pandas as pd

data = yf.download("RELIANCE.NS", start="2023-01-01", end="2024-01-01")
benchmark_data = yf.download("^NSEI", start="2023-01-01", end="2024-01-01")

print("Columns in data:", data.columns)

close_col = 'Adj Close' if 'Adj Close' in data.columns else 'Close'

# Calculate daily returns
data['Returns'] = data[close_col].pct_change()
benchmark_data['Benchmark_Returns'] = benchmark_data[close_col].pct_change()


rf = 0.06 / 252


sharpe = (data['Returns'].mean() - rf) / data['Returns'].std()

neg_returns = data['Returns'][data['Returns'] < 0]
sortino = (data['Returns'].mean() - rf) / neg_returns.std()


cumulative = (1 + data['Returns']).cumprod()
rolling_max = cumulative.cummax()
drawdown = (cumulative - rolling_max) / rolling_max
max_dd = drawdown.min()


win_rate = (data['Returns'] > 0).mean()


profits = data['Returns'][data['Returns'] > 0]
losses = data['Returns'][data['Returns'] < 0]
profit_factor = profits.sum() / abs(losses.sum())
avg_profit = profits.mean()
avg_loss = losses.mean()
max_profit = profits.max()
max_loss = losses.min()


reliance_cum_return = (1 + data['Returns']).prod() - 1
nifty_cum_return = (1 + benchmark_data['Benchmark_Returns']).prod() - 1
relative_perf = reliance_cum_return - nifty_cum_return

`
print(f"📈 Sharpe Ratio: {sharpe:.3f}")
print(f"📉 Sortino Ratio: {sortino:.3f}")
print(f"📉 Max Drawdown: {max_dd:.2%}")
print(f"✅ Win Rate: {win_rate:.2%}")
print(f"💰 Profit Factor: {profit_factor:.2f}")
print(f"   ↳ Avg Profit: {avg_profit:.2%}, Avg Loss: {avg_loss:.2%}")
print(f"   ↳ Max Profit: {max_profit:.2%}, Max Loss: {max_loss:.2%}")
print(f"🇮🇳 RELIANCE Return: {reliance_cum_return:.2%}")
print(f"📊 NIFTY50 Return: {nifty_cum_return:.2%}")
print(f"🆚 Relative Outperformance: {relative_perf:.2%}")
[*********************100%***********************]  1 of 1 completed
[*********************100%***********************]  1 of 1 completed
Columns in data: MultiIndex([( 'Close', 'RELIANCE.NS'),
            (  'High', 'RELIANCE.NS'),
            (   'Low', 'RELIANCE.NS'),
            (  'Open', 'RELIANCE.NS'),
            ('Volume', 'RELIANCE.NS')],
           names=['Price', 'Ticker'])
📈 Sharpe Ratio: 0.016
📉 Sortino Ratio: 0.028
📉 Max Drawdown: -15.23%
✅ Win Rate: 50.20%
💰 Profit Factor: 1.11
   ↳ Avg Profit: 0.86%, Avg Loss: -0.79%
   ↳ Max Profit: 4.31%, Max Loss: -3.10%
🇮🇳 RELIANCE Return: 9.11%
📊 NIFTY50 Return: 19.42%
🆚 Relative Outperformance: -10.31%

In [7]:
import yfinance as yf
import pandas as pd

# Download historical data
data = yf.download('RELIANCE.NS', start='2023-01-01', end='2024-01-01')

# Calculate moving averages
data['SMA50'] = data['Close'].rolling(window=50).mean()
data['SMA200'] = data['Close'].rolling(window=200).mean()

# Generate trading signals
data['Signal'] = 0  
data.loc[data['SMA50'] > data['SMA200'], 'Signal'] = 1  
data.loc[data['SMA50'] < data['SMA200'], 'Signal'] = -1  

print(data[['Close', 'SMA50', 'SMA200', 'Signal']].tail(10))

# Margin calculations
data['Trade_Value'] = data['Close']  # Assuming full position entry at close price
data['Margin_Required'] = data['Trade_Value'] * 0.20  # 20% margin requirement
initial_capital = 100000  # Example starting capital
data['Margin_Utilization'] = data['Margin_Required'] / initial_capital * 100  # Percentage of capital used

# Risk measurements
data['Returns'] = data['Close'].pct_change()
data['Volatility'] = data['Returns'].rolling(window=50).std()
data['Max_Drawdown'] = (data['Close'] - data['Close'].cummax()) / data['Close'].cummax()

print(data[['Margin_Required', 'Margin_Utilization', 'Returns', 'Volatility', 'Max_Drawdown']].tail(10))
[*********************100%***********************]  1 of 1 completed

1 Failed download:
['RELIANCE.NS']: YFRateLimitError('Too Many Requests. Rate limited. Try after a while.')
Empty DataFrame
Columns: [(Close, RELIANCE.NS), (SMA50, ), (SMA200, ), (Signal, )]
Index: []
Empty DataFrame
Columns: [(Margin_Required, ), (Margin_Utilization, ), (Returns, ), (Volatility, ), (Max_Drawdown, )]
Index: []
In [ ]: